Adds wunderlist agent

Dominik Sander 9 years ago
parent
commit
292f455b56

+ 1 - 0
Gemfile

@@ -34,6 +34,7 @@ gem 'omniauth-dropbox'
34 34
 # Optional Services.
35 35
 gem 'omniauth-37signals'          # BasecampAgent
36 36
 # gem 'omniauth-github'
37
+gem 'omniauth-wunderlist', github: 'wunderlist/omniauth-wunderlist', ref: 'd0910d0396107b9302aa1bc50e74bb140990ccb8'
37 38
 
38 39
 # Bundler <1.5 does not recognize :x64_mingw as a valid platform name.
39 40
 # Unfortunately, it can't self-update because it errors when encountering :x64_mingw.

+ 10 - 0
Gemfile.lock

@@ -8,6 +8,15 @@ GIT
8 8
       http_parser.rb (~> 0.6.0)
9 9
       simple_oauth (~> 0.2.0)
10 10
 
11
+GIT
12
+  remote: git://github.com/wunderlist/omniauth-wunderlist.git
13
+  revision: d0910d0396107b9302aa1bc50e74bb140990ccb8
14
+  ref: d0910d0396107b9302aa1bc50e74bb140990ccb8
15
+  specs:
16
+    omniauth-wunderlist (0.0.1)
17
+      omniauth (~> 1.0)
18
+      omniauth-oauth2 (~> 1.1)
19
+
11 20
 GEM
12 21
   remote: https://rubygems.org/
13 22
   specs:
@@ -495,6 +504,7 @@ DEPENDENCIES
495 504
   omniauth-dropbox
496 505
   omniauth-tumblr
497 506
   omniauth-twitter
507
+  omniauth-wunderlist!
498 508
   pg
499 509
   protected_attributes (~> 1.0.8)
500 510
   pry

+ 2 - 2
app/assets/stylesheets/application.css.scss.erb

@@ -245,8 +245,8 @@ h2 .scenario, a span.label.scenario {
245 245
   width: 200px;
246 246
 }
247 247
 
248
-$services:            twitter     37signals   github      tumblr      dropbox;
249
-$service-colors:      #55acee     #8fc857     #444444     #2c4762     #007EE5;
248
+$services:            twitter     37signals   github      tumblr      dropbox   wunderlist;
249
+$service-colors:      #55acee     #8fc857     #444444     #2c4762     #007EE5   #ED5F27;
250 250
 
251 251
 @mixin services {
252 252
   @each $service in $services {

+ 2 - 0
app/helpers/application_helper.rb

@@ -57,6 +57,8 @@ module ApplicationHelper
57 57
     case provider.to_sym
58 58
     when :twitter, :tumblr, :github, :dropbox
59 59
       icon_tag("fa-#{provider}")
60
+    when :wunderlist
61
+      icon_tag("fa-list")
60 62
     else
61 63
       icon_tag("fa-lock")
62 64
     end

+ 74 - 0
app/models/agents/wunderlist_agent.rb

@@ -0,0 +1,74 @@
1
+module Agents
2
+  class WunderlistAgent < Agent
3
+    include FormConfigurable
4
+    include Oauthable
5
+    valid_oauth_providers :wunderlist
6
+
7
+    cannot_be_scheduled!
8
+
9
+    description <<-MD
10
+      The WunderlistAgent creates new new tasks based on the incoming event.
11
+
12
+      To be able to use this Agent you need to authenticate with Wunderlist in the [Services](/services) section first.
13
+
14
+    MD
15
+
16
+    def default_options
17
+      {
18
+        'list_id' => '',
19
+        'title' => '{{title}}'
20
+      }
21
+    end
22
+
23
+    form_configurable :list_id, roles: :completable
24
+    form_configurable :title
25
+
26
+    def complete_list_id
27
+      response = request_guard do
28
+        HTTParty.get lists_url, request_options
29
+      end
30
+      response.map { |p| {text: "#{p['title']} (#{p['id']})", id: p['id']}}
31
+    end
32
+
33
+    def validate_options
34
+      errors.add(:base, "you need to specify the list you want to add tasks to") unless options['list_id'].present?
35
+      errors.add(:base, "you need to specify the title of the task to create") unless options['title'].present?
36
+    end
37
+
38
+    def working?
39
+      !recent_error_logs?
40
+    end
41
+
42
+    def receive(incoming_events)
43
+      incoming_events.each do |event|
44
+        mo = interpolated(event)
45
+        title = mo[:title][0..244]
46
+        log("Creating new task '#{title}' on list #{mo[:list_id]}", inbound_event: event)
47
+        request_guard do
48
+          HTTParty.post tasks_url, request_options.merge(body: {title: title, list_id: mo[:list_id].to_i}.to_json)
49
+        end
50
+      end
51
+    end
52
+  private
53
+    def request_guard(&blk)
54
+      response = yield
55
+      error("Error during http request: #{response.body}") if response.code > 400
56
+      response
57
+    end
58
+
59
+    def lists_url
60
+      "https://a.wunderlist.com/api/v1/lists"
61
+    end
62
+
63
+    def tasks_url
64
+      "https://a.wunderlist.com/api/v1/tasks"
65
+    end
66
+
67
+    def request_options
68
+      {:headers => {'Content-Type' => 'application/json',
69
+                    'User-Agent' => 'Huginn (https://github.com/cantino/huginn)',
70
+                    'X-Access-Token' => service.token,
71
+                    'X-Client-ID' => ENV["WUNDERLIST_OAUTH_KEY"] }}
72
+    end
73
+  end
74
+end

+ 6 - 0
config/initializers/devise.rb

@@ -263,6 +263,12 @@ Devise.setup do |config|
263 263
     config.omniauth :dropbox, key, secret
264 264
   end
265 265
 
266
+  if defined?(OmniAuth::Strategies::Wunderlist) &&
267
+     (key = ENV["WUNDERLIST_OAUTH_KEY"]).present? &&
268
+     (secret = ENV["WUNDERLIST_OAUTH_SECRET"]).present?
269
+    config.omniauth :wunderlist, key, secret
270
+  end
271
+
266 272
   # ==> Warden configuration
267 273
   # If you want to use other strategies, that are not supported by Devise, or
268 274
   # change the failure app, you can configure them inside the config.warden block.

+ 1 - 0
config/locales/devise.en.yml

@@ -32,6 +32,7 @@ en:
32 32
       github: "GitHub"
33 33
       37signals: "37Signals (Basecamp)"
34 34
       dropbox: "Dropbox"
35
+      wunderlist: 'Wunderlist'
35 36
     passwords:
36 37
       no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
37 38
       send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."

+ 1 - 0
spec/env.test

@@ -7,4 +7,5 @@ THIRTY_SEVEN_SIGNALS_OAUTH_KEY=TESTKEY
7 7
 THIRTY_SEVEN_SIGNALS_OAUTH_SECRET=TESTSECRET
8 8
 DROPBOX_OAUTH_KEY=dropboxoauthkey
9 9
 DROPBOX_OAUTH_SECRET=dropboxoauthsecret
10
+WUNDERLIST_OAUTH_KEY=wunderoauthkey
10 11
 FAILED_JOBS_TO_KEEP=2

+ 74 - 0
spec/models/agents/wunderlist_agent_spec.rb

@@ -0,0 +1,74 @@
1
+require 'spec_helper'
2
+require 'models/concerns/oauthable'
3
+
4
+describe Agents::WunderlistAgent do
5
+  it_behaves_like Oauthable
6
+
7
+  before(:each) do
8
+
9
+    @valid_params = {
10
+                      'list_id' => '12345',
11
+                      'title' => '{{title}}: {{url}}',
12
+                    }
13
+
14
+    @checker = Agents::WunderlistAgent.new(:name => "somename", :options => @valid_params)
15
+    @checker.user = users(:jane)
16
+    @checker.service = services(:generic)
17
+    @checker.save!
18
+
19
+    @event = Event.new
20
+    @event.agent = agents(:bob_weather_agent)
21
+    @event.payload = { title: 'hello', url: 'www.example.com'}
22
+    @event.save!
23
+  end
24
+
25
+  describe "validating" do
26
+    before do
27
+      expect(@checker).to be_valid
28
+    end
29
+
30
+    it "should require the title" do
31
+      @checker.options['title'] = nil
32
+      expect(@checker).not_to be_valid
33
+    end
34
+
35
+    it "should require the list_id" do
36
+      @checker.options['list_id'] = nil
37
+      expect(@checker).not_to be_valid
38
+    end
39
+  end
40
+
41
+  it "should generate the request_options" do
42
+    expect(@checker.send(:request_options)).to eq({:headers=>{"Content-Type"=>"application/json", "User-Agent"=>"Huginn (https://github.com/cantino/huginn)", "X-Access-Token"=>"1234token", "X-Client-ID"=>"wunderoauthkey"}})
43
+  end
44
+
45
+  describe "#complete_list_id" do
46
+    it "should return a array of hashes" do
47
+      stub_request(:get, 'https://a.wunderlist.com/api/v1/lists').to_return(
48
+        :body => JSON.dump([{title: 'test', id: 12345}]),
49
+        :headers => {"Content-Type" => "text/json"}
50
+      )
51
+      expect(@checker.complete_list_id).to eq([{:text=>"test (12345)", :id=>12345}])
52
+    end
53
+  end
54
+
55
+  describe "#receive" do
56
+    it "send a message to the hipchat" do
57
+      stub_request(:post, 'https://a.wunderlist.com/api/v1/tasks').with { |request| request.body == 'abc'}
58
+      @checker.receive([@event])
59
+    end
60
+  end
61
+
62
+  describe "#working?" do
63
+    it "should be working with no entry in the error log" do
64
+      expect(@checker).to be_working
65
+    end
66
+
67
+    it "should not be working with a recent entry in the error log" do
68
+      @checker.error("test")
69
+      @checker.reload
70
+      @checker.last_event_at = Time.now
71
+      expect(@checker).to_not be_working
72
+    end
73
+  end
74
+end